package com.hup.utils.swing.model;

import com.hup.utils.commons.NameSorter;
import lombok.Getter;

import javax.swing.*;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Comparator;
import java.util.Vector;
import java.util.function.Function;

/**
 * {@link JList}
 * 强化 {@link DefaultListModel}
 * .提供 addAll方法
 * .提供排序方法
 *
 * @author hugan
 * @date 2020/4/29
 */
public class DefaultListModel2<E> extends DefaultListModel<E> {

    @Getter
    private Vector<E> delegate;

    @SuppressWarnings("unchecked")
    public DefaultListModel2() {
        try {
            Field fDelegate = this.getClass().getSuperclass().getDeclaredField("delegate");
            fDelegate.setAccessible(true);
            delegate = (Vector<E>) fDelegate.get(this);
        } catch (Exception e) {
            throw new IllegalArgumentException("获取delegate错误?:" + e.getMessage());
        }
    }

    /**
     * @param data 要添加的数据
     * @param clear 是否清空原有数据
     * @apiNote 有add的情况下只会触发一次 fireIntervalAdded 事件
     */
    public void addAll(Collection<E> data, boolean clear) {
        int oldSize = delegate.size();
        int addSize = data.size();
        if (addSize == 0) {
            if (clear) clear();
            return;
        }

        if (clear) delegate.clear();
        delegate.addAll(data);
        /*
        这里的index可能会对swing固有的逻辑有影响;目前不会深究!!
        swing实在太臃肿,学习成本太高,真的不科学
         */
        if (clear) {
            //ed是不被包含的index
            fireIntervalAdded(this, 0, addSize);
        } else {
            fireIntervalAdded(this, oldSize, oldSize + addSize);
        }
    }

    public void sort(Comparator<? super E> c) {
        delegate.sort(c);
        fireContentsChanged(this, 0, delegate.size());
    }

    public void sortByName(Function<E, String> nameGetter) {
        NameSorter.sortByName(delegate, nameGetter);
        fireContentsChanged(this, 0, delegate.size());
    }

    /**
     * 通知某item刷新
     * @apiNote 本方法实际上还是让JList重绘了n个子item,swing的坑太深了╮(╯_╰)╭
     */
    public void fireItemChanged(int index) {
        fireContentsChanged(this, index, index);
    }

}
